package com.lz.frame.config.security;


import java.util.*;
import com.lz.frame.annotation.AnonymousAccess;
import com.lz.frame.domain.VO.UserVO;
import com.lz.frame.domain.entity.User;
import com.lz.frame.domain.mapper.UserMapper;
import com.lz.frame.domain.service.UserLoginService;
import com.lz.frame.filter.filter.ZzOncePerRequestFilter;
import com.lz.frame.utils.ReqMapperUtil;
import com.lz.frame.utils.SpringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启了权限校验
@Configuration
//@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter implements UserDetailsService {
    private static final String DEV = "dev";
    //第一步：实现查询用户信息 - -  返回的UserDetail会经常使用
    // 第二步：使用密码加密器  - - 未使用加密器，需要在数据库中的密码前缀添加“{noop}”  每次生成的密码都不一样 所以数据库的密码也不是唯一的  与之相反的是JWT 它每次加解密都是固定的
    // 第三步：放行一个用户的登录接口

    @Resource
    private UserMapper userMapper;

    @Value("${spring.profiles.active}")
    private String activeProfile;
    @Resource
    private ZzOncePerRequestFilter lzOncePerRequestFilter;

    static Set<String> anonymousAccessUrlsSet = new HashSet<>(Arrays.asList(
            "/security/login",
            "/swagger-ui.html",
            "/",
            "/favicon.ico",
            "/**/*.html",
            "/**/*.css",
            "/**/*.js",
            "/swagger-ui/**",
            "/webjars/**",
            "/v2/**",
            "/v3/api-docs/**",
            "/swagger-resources/**"
            , "/gator.volces.com/list"

    ));


    /**
     * 根据用户名查询用户以及对应的权限信息
     * 封装成UserDetails对象返回
     *
     * @param username 用户名
     * @return UserDetails (封装整个用户信息，然后完善接口)
     * @throws UsernameNotFoundException
     */
//    @Override
//    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//        User userByUsername = userMapper.getUserByUsername(username);
//        MyUserDetails myUserDetails = new MyUserDetails(userByUsername);
//        return myUserDetails;
//    }

    @Resource
    private UserLoginService userLoginService;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.getUserByUsername(username);
        UserVO userVO = userLoginService.getUserByUserId(user);
        MyUserDetails02 myUserDetails = new MyUserDetails02(userVO);
        return myUserDetails;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 改进匿名访问配置
                .antMatchers(getAnonymousAccessUrls().toArray(new String[0])).permitAll()
                .anyRequest().authenticated()
                .and();
        http.addFilterBefore(lzOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    //自定义拦截不能放行static资源

    /**
     * 在user登录的时候调用，可以调用loadUserByUsername方法获取用户信息
     *
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 没有这个密码工具会，使用默认的加密方法。即在数据库中的密码需要有一个古荡的前缀{noop}
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    public List<String> getAnonymousAccessUrls() {
        String activeProfile = SpringUtil.getActiveProfile();
        if (!activeProfile.equals(DEV)) {
            return Collections.emptyList();
        }
        List<String> anonymousAccessUrls = ReqMapperUtil.getAnonymousAccessUrls(AnonymousAccess.class);
        anonymousAccessUrls.addAll(anonymousAccessUrlsSet);
        anonymousAccessUrls.add("/demo/demo");
        return anonymousAccessUrls;
    }

}